/* * Copyright (C) 2011 Everit Kft. (http://everit.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.everit.osgi.dev.maven; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import javax.management.InstanceNotFoundException; import javax.management.IntrospectionException; import javax.management.ReflectionException; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.resolution.ArtifactRequest; import org.everit.osgi.dev.dist.util.DistConstants; import org.everit.osgi.dev.dist.util.attach.EOSGiVMManager; import org.everit.osgi.dev.dist.util.attach.EOSGiVMManagerParameter; import org.everit.osgi.dev.dist.util.attach.EnvironmentRuntimeInfo; import org.everit.osgi.dev.dist.util.configuration.DistributedEnvironmentConfigurationProvider; import org.everit.osgi.dev.dist.util.configuration.schema.ArtifactType; import org.everit.osgi.dev.dist.util.configuration.schema.ArtifactsType; import org.everit.osgi.dev.dist.util.configuration.schema.EntryType; import org.everit.osgi.dev.dist.util.configuration.schema.EnvironmentType; import org.everit.osgi.dev.dist.util.configuration.schema.ParsableType; import org.everit.osgi.dev.dist.util.configuration.schema.ParsablesType; import org.everit.osgi.dev.dist.util.configuration.schema.PropertiesType; import org.everit.osgi.dev.dist.util.configuration.schema.TemplateEnginesType; import org.everit.osgi.dev.dist.util.configuration.schema.UseByType; import org.everit.osgi.dev.maven.configuration.EnvironmentConfiguration; import org.everit.osgi.dev.maven.configuration.LaunchConfig; import org.everit.osgi.dev.maven.configuration.LaunchConfigOverride; import org.everit.osgi.dev.maven.dto.DistributedEnvironmentData; import org.everit.osgi.dev.maven.upgrade.BundleSNV; import org.everit.osgi.dev.maven.upgrade.NoopRemoteOSGiManager; import org.everit.osgi.dev.maven.upgrade.RemoteOSGiManager; import org.everit.osgi.dev.maven.upgrade.RuntimeBundleInfo; import org.everit.osgi.dev.maven.upgrade.jmx.JMXOSGiManager; import org.everit.osgi.dev.maven.util.BundleExecutionPlan; import org.everit.osgi.dev.maven.util.DistUtil; import org.everit.osgi.dev.maven.util.DistributableArtifact; import org.everit.osgi.dev.maven.util.EnvironmentCleaner; import org.everit.osgi.dev.maven.util.FileManager; import org.everit.osgi.dev.maven.util.PluginUtil; import org.osgi.framework.Bundle; /** * Creates a distribution package for the project. Distribution packages may be provided as * Environment parameters or 'equinox', the default option, -may also be used. The structure of the * distribution package may be different for different types. */ @Mojo(name = "dist", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, requiresDependencyResolution = ResolutionScope.COMPILE) @Execute(phase = LifecyclePhase.PACKAGE) public class DistMojo extends AbstractEOSGiMojo { private static final int MAVEN_ARTIFACT_ID_PART_NUM = 3; private static final Set<String> RESERVED_SYSPROPS; private static final String VAR_DIST_UTIL = "distUtil"; static { RESERVED_SYSPROPS = new HashSet<>(); RESERVED_SYSPROPS.add(DistConstants.SYSPROP_ENVIRONMENT_ID); RESERVED_SYSPROPS.add(DistConstants.SYSPROP_LAUNCH_UNIQUE_ID); } protected DistributedEnvironmentConfigurationProvider distEnvConfigProvider = new DistributedEnvironmentConfigurationProvider(); /** * Path to folder where the distribution will be generated. The content of this folder will be * overridden if the files with same name already exist. * */ @Parameter(property = "eosgi.distFolder", defaultValue = "${project.build.directory}/eosgi/dist") protected String distFolder; protected List<DistributedEnvironmentData> distributedEnvironmentDataCollection; @Parameter(defaultValue = "${localRepository}") protected ArtifactRepository localRepository; /** * Map of plugin artifacts. */ @Parameter(defaultValue = "${plugin.artifactMap}", required = true, readonly = true) protected Map<String, org.apache.maven.artifact.Artifact> pluginArtifactMap; @Parameter(defaultValue = "${session}", readonly = true) protected MavenSession session; /** * The directory where there may be additional files to create the distribution package * (optional). */ @Parameter(property = "eosgi.sourceDistFolder", defaultValue = "${basedir}/src/dist/") protected String sourceDistFolder; private void checkAndAddReservedLaunchConfigurationProperties( final EnvironmentConfiguration environment, final LaunchConfig launchConfig) throws MojoFailureException { checkReservedSystemPropertyInVmArguments(launchConfig.getVmArguments()); LaunchConfigOverride[] overrides = launchConfig.getOverrides(); if (overrides != null) { for (LaunchConfigOverride launchConfigOverride : overrides) { checkReservedSystemPropertyInVmArguments(launchConfigOverride.getVmArguments()); } } launchConfig.getVmArguments().put(DistConstants.SYSPROP_ENVIRONMENT_ID, "-D" + DistConstants.SYSPROP_ENVIRONMENT_ID + "=" + environment.getId()); } private void checkReservedSystemPropertyInVmArguments(final Map<String, String> vmArguments) throws MojoFailureException { if (vmArguments == null) { return; } for (Entry<String, String> entry : vmArguments.entrySet()) { if (RESERVED_SYSPROPS.contains(entry.getKey())) { throw new MojoFailureException("'" + entry.getKey() + "' cannot be specified as the key of a VM argument manually" + " as it is a reserved word."); } String value = entry.getValue(); if (value != null) { if (value.startsWith("-D")) { value = value.substring(2); } int indexOfEqual = value.indexOf('='); if (indexOfEqual >= 0) { value = value.substring(0, indexOfEqual); } if (RESERVED_SYSPROPS.contains(value)) { throw new MojoFailureException("'" + value + "' cannot be specified as a system property manually as it is a reserved word."); } } } } /** * On Equinox there is an exception if we do not wait 1-30 seconds with bundle update command * after we overcopied the file. Therefore it is better to reinstall them. * * @param bundleExecutionPlan * The original execution plan that is modified. */ private void convertBundleUpdatesToUninstallAndInstall( final BundleExecutionPlan bundleExecutionPlan) { for (DistributableArtifact updatableArtifact : bundleExecutionPlan.updateBundles) { bundleExecutionPlan.uninstallBundles.add(updatableArtifact); bundleExecutionPlan.installBundles.add(updatableArtifact); bundleExecutionPlan.changeStartLevelIfInitialBundleStartLevelChangesOnBundles .remove(updatableArtifact); bundleExecutionPlan.higherStartLevelOnBundles.remove(updatableArtifact); bundleExecutionPlan.lowerStartLevelOnBundles.remove(updatableArtifact); bundleExecutionPlan.setInitialStartLevelOnBundles.remove(updatableArtifact); bundleExecutionPlan.setStartLevelFromInitialBundles.remove(updatableArtifact); bundleExecutionPlan.startStoppedBundles.remove(updatableArtifact); bundleExecutionPlan.stopStartedBundles.remove(updatableArtifact); } bundleExecutionPlan.updateBundles.clear(); } private void copyDistFolderToTargetIfExists(final File environmentRootFolder, final FileManager fileManager) throws MojoExecutionException { if (sourceDistFolder != null) { File sourceDistPathFile = new File(sourceDistFolder); if (sourceDistPathFile.exists() && sourceDistPathFile.isDirectory()) { fileManager.copyDirectory(sourceDistPathFile, environmentRootFolder); } } } /** * Creates an EOSGi VM Manager. * * @return The EOSGi VM Manager. */ protected EOSGiVMManager createEOSGiVMManager() { EOSGiVMManagerParameter parameter = new EOSGiVMManagerParameter(); parameter.classLoader = resolveAttachAPIClassLoader(); parameter.deadlockEventHandler = (eventData) -> { getLog().warn("Deadlock during reading info of VM with id '" + eventData.virtualMachineId + "'. Trying to refresh VM list again."); eventData.vmManager.refresh(); }; parameter.attachNotSupportedExceptionDuringRefreshEventHandler = (eventData) -> { getLog().warn("Cannot attach JVM '" + eventData.virtualMachineId + "' with message: " + eventData.cause.getMessage()); }; return new EOSGiVMManager(parameter); } private Map<BundleSNV, DistributableArtifact> createJustStartedBundleByUniqueLabelMap( final Collection<DistributableArtifact> justStartedBundles) { Map<BundleSNV, DistributableArtifact> justStartedBundleByUniqueLabel = new HashMap<>(); for (DistributableArtifact dArtifact : justStartedBundles) { justStartedBundleByUniqueLabel.put(toBundleSNV(dArtifact), dArtifact); } return justStartedBundleByUniqueLabel; } private RemoteOSGiManager createRemoteOSGiManager(final String environmentId, final File distFolderFile, final BundleExecutionPlan bundleExecutionPlan, final EnvironmentType existingDistributedEnvironment, final EOSGiVMManager virtualMachineManager) throws MojoExecutionException { Set<EnvironmentRuntimeInfo> runtimeInformations = virtualMachineManager.getRuntimeInformations(environmentId, distFolderFile); if (runtimeInformations.isEmpty()) { return new NoopRemoteOSGiManager(); } if (runtimeInformations.size() > 1) { StringBuilder sb = new StringBuilder(); for (EnvironmentRuntimeInfo environmentRuntimeInfo : runtimeInformations) { if (sb.length() > 0) { sb.append(','); } sb.append(environmentRuntimeInfo.virtualMachineId); } throw new MojoExecutionException( "Found multiple running JVMs that belong to the environment." + " Live upgrade is supported only on one running JVM:'" + environmentId + "', virtualMachines = '" + sb.toString() + "'"); } EnvironmentRuntimeInfo runtimeInfo = runtimeInformations.iterator().next(); if (existingDistributedEnvironment == null) { throw new MojoExecutionException( "Found JVM that belongs to Environment, but there is no distributed environment in the" + " file system. Try stopping the Environment JVM before runnign the distribution" + " upgrade: [environmentId = '" + environmentId + "', virtualMachines = '" + runtimeInfo.virtualMachineId + "'"); } if (isBundleExecutionPlanEmpty(bundleExecutionPlan)) { return new NoopRemoteOSGiManager(); } String jmxServiceURL = runtimeInfo.jmxServiceURL; if (jmxServiceURL == null) { throw new MojoExecutionException("Bundle changes cannot be applied on the running OSGi" + " container as JMX service URL is not available: {environmentId : \"" + environmentId + "\", virtualMachine : \"" + runtimeInfo.virtualMachineId + "\"}"); } try { return new JMXOSGiManager(jmxServiceURL, getLog()); } catch (IOException | InstanceNotFoundException | IntrospectionException | ReflectionException e) { throw new MojoExecutionException( "Could not connect to OSGi Environment: {environmentId : \"" + environmentId + "\", virtualMachines : \"" + runtimeInfo.virtualMachineId + "\", jmxService : \"" + jmxServiceURL + "\"}", e); } } private Map<BundleSNV, DistributableArtifact> createStartActionBundleByUniqueLabelMap( final Collection<DistributableArtifact> distributedArtifacts) { Map<BundleSNV, DistributableArtifact> shouldBeActiveBundleByUniqueLabel = new HashMap<>(); for (DistributableArtifact artifact : distributedArtifacts) { if (EOSGiConstants.BUNDLE_ACTION_START.equals(resolveBundleAction(artifact))) { shouldBeActiveBundleByUniqueLabel.put(toBundleSNV(artifact), artifact); } } return shouldBeActiveBundleByUniqueLabel; } private void distributeArtifactFiles(final File envDistFolderFile, final Collection<DistributableArtifact> dArtifacts, final FileManager fileManager) throws MojoExecutionException { for (DistributableArtifact dArtifact : dArtifacts) { Artifact mavenArtifact = resolveMavenArtifactByArtifactType(dArtifact); File targetFile = PluginUtil.resolveArtifactAbsoluteFile(dArtifact, mavenArtifact, envDistFolderFile); fileManager.overCopyFile(mavenArtifact.getFile(), targetFile); } } @Override protected void doExecute() throws MojoExecutionException, MojoFailureException { try (EOSGiVMManager virtualMachineManager = createEOSGiVMManager()) { File globalDistFolderFile = new File(distFolder); distributedEnvironmentDataCollection = new ArrayList<>(); EnvironmentConfiguration[] environmentsToProcess = getEnvironmentsToProcess(); Map<String, DistributableArtifact> projectDistributableDependencies = createDistributableArtifactsByGAVFromProjectDeps(); for (EnvironmentConfiguration environment : environmentsToProcess) { executeOnEnvironment(globalDistFolderFile, environment, projectDistributableDependencies, virtualMachineManager); } } } private void executeOnEnvironment(final File globalDistFolderFile, final EnvironmentConfiguration environment, final Map<String, DistributableArtifact> projectDistributableDependencies, final EOSGiVMManager virtualMachineManager) throws MojoExecutionException, MojoFailureException { FileManager fileManager = new FileManager(); Collection<DistributableArtifact> distributableArtifacts = generateDistributableArtifactsForEnvironment( environment, projectDistributableDependencies); String environmentId = environment.getId(); Artifact distPackageArtifact = resolveDistPackage(environment.getFramework()); File distPackageFile = distPackageArtifact.getFile(); File environmentRootFolder = new File(globalDistFolderFile, environmentId); File environmentConfigurationFile = new File(environmentRootFolder, DistConstants.FILE_NAME_EOSGI_DIST_CONFIG); EnvironmentType existingDistributedEnvironment = distEnvConfigProvider .getOverriddenDistributedEnvironmentConfig(environmentConfigurationFile, UseByType.PARSABLES); Collection<DistributableArtifact> existingDistributedArtifacts = processArtifacts( existingDistributedEnvironment); File environmentConfigurationTempFile = unpackDistConfigFileToNewTempFile(distPackageFile, fileManager); processConfigurationTemplate(environmentConfigurationTempFile, distributableArtifacts, environment, fileManager); EnvironmentType distributedEnvironment = distEnvConfigProvider .getOverriddenDistributedEnvironmentConfig(environmentConfigurationTempFile, UseByType.PARSABLES); fileManager.unpackZipFile(distPackageFile, environmentRootFolder, DistConstants.FILE_NAME_EOSGI_DIST_CONFIG); copyDistFolderToTargetIfExists(environmentRootFolder, fileManager); Collection<DistributableArtifact> newDistributedArtifacts = processArtifacts(distributedEnvironment); BundleExecutionPlan bundleExecutionPlan = new BundleExecutionPlan(environment.getId(), existingDistributedArtifacts, newDistributedArtifacts, environmentRootFolder, artifactResolver); fileManager.overCopyFile(environmentConfigurationTempFile, environmentConfigurationFile); environmentConfigurationTempFile.delete(); convertBundleUpdatesToUninstallAndInstall(bundleExecutionPlan); try (RemoteOSGiManager remoteOSGiManager = createRemoteOSGiManager(environmentId, environmentRootFolder, bundleExecutionPlan, existingDistributedEnvironment, virtualMachineManager)) { int originalFrameworkStartLevel = remoteOSGiManager.getFrameworkStartLevel(); int frameworkStartLevelAfterUpgrade = resolveFrameworkStartLevelAfterUpgrade( distributedEnvironment.getFrameworkStartLevel(), originalFrameworkStartLevel); int currentInitialBundleStartLevel = remoteOSGiManager.getInitialBundleStartLevel(); int newInitialBundleStartLevel = (distributedEnvironment.getInitialBundleStartLevel() != null) ? distributedEnvironment.getInitialBundleStartLevel() : currentInitialBundleStartLevel; int frameworkStartLevelDuringUpdate = resolveNecessaryStartlevel(bundleExecutionPlan, originalFrameworkStartLevel, currentInitialBundleStartLevel); try { if (frameworkStartLevelDuringUpdate < originalFrameworkStartLevel) { remoteOSGiManager.setFrameworkStartLevel(frameworkStartLevelDuringUpdate); } remoteOSGiManager.stopBundles(toBundleSNVs(bundleExecutionPlan.updateBundles)); remoteOSGiManager.stopBundles(toBundleSNVs(bundleExecutionPlan.stopStartedBundles)); higherBundleStartLevelWhereNecessary(bundleExecutionPlan, currentInitialBundleStartLevel, newInitialBundleStartLevel, remoteOSGiManager); remoteOSGiManager.uninstallBundles(toBundleSNVs(bundleExecutionPlan.uninstallBundles)); if (newInitialBundleStartLevel != currentInitialBundleStartLevel) { remoteOSGiManager.setInitialBundleStartLevel(newInitialBundleStartLevel); } distributeArtifactFiles(environmentRootFolder, newDistributedArtifacts, fileManager); remoteOSGiManager .installBundles(toBundleSNVLocationMap(bundleExecutionPlan.installBundles)); setStartLevelOnNewlyInstalledBundles(bundleExecutionPlan.installBundles, remoteOSGiManager); remoteOSGiManager.updateBundles(toBundleSNVs(bundleExecutionPlan.updateBundles)); remoteOSGiManager.resolveAll(); remoteOSGiManager.refresh(); lowerBundleStartLevelWhereNecessary(bundleExecutionPlan, currentInitialBundleStartLevel, newInitialBundleStartLevel, remoteOSGiManager); parseParsables(environmentRootFolder, distributedEnvironment, newDistributedArtifacts, fileManager); startBundlesWhereNecessary(bundleExecutionPlan, newDistributedArtifacts, remoteOSGiManager); distributedEnvironmentDataCollection.add(new DistributedEnvironmentData(environment, distributedEnvironment, environmentRootFolder, newDistributedArtifacts)); EnvironmentCleaner.cleanEnvironmentFolder(distributedEnvironment, environmentRootFolder, fileManager); } finally { if (frameworkStartLevelAfterUpgrade != frameworkStartLevelDuringUpdate) { remoteOSGiManager.setFrameworkStartLevel(frameworkStartLevelAfterUpgrade); } } } } private void higherBundleStartLevelWhereNecessary(final BundleExecutionPlan bundleExecutionPlan, final int currentInitialBundleStartLevel, final int newInitialBundleStartLevel, final RemoteOSGiManager remoteOSGiManager) { if (newInitialBundleStartLevel > currentInitialBundleStartLevel) { for (DistributableArtifact dArtifact : bundleExecutionPlan.changeStartLevelIfInitialBundleStartLevelChangesOnBundles) { // CS_DISABLE_LINE_LENGTH remoteOSGiManager.setBundleStartLevel(toBundleSNV(dArtifact), newInitialBundleStartLevel); } } for (DistributableArtifact dArtifact : bundleExecutionPlan.higherStartLevelOnBundles) { remoteOSGiManager.setBundleStartLevel(toBundleSNV(dArtifact), resolveStartLevel(dArtifact)); } for (Entry<DistributableArtifact, Integer> artifactWithOldSL : bundleExecutionPlan.setInitialStartLevelOnBundles // CS_DISABLE_LINE_LENGTH .entrySet()) { int oldStartLevel = artifactWithOldSL.getValue(); if (oldStartLevel < newInitialBundleStartLevel) { remoteOSGiManager.setBundleStartLevel(toBundleSNV(artifactWithOldSL.getKey()), newInitialBundleStartLevel); } } for (DistributableArtifact dArtifact : bundleExecutionPlan.setStartLevelFromInitialBundles) { Integer startLevel = resolveStartLevel(dArtifact); if (startLevel.compareTo(newInitialBundleStartLevel) > 0) { remoteOSGiManager.setBundleStartLevel(toBundleSNV(dArtifact), startLevel); } } } private boolean isBundleExecutionPlanEmpty(final BundleExecutionPlan bundleExecutionPlan) { return bundleExecutionPlan.installBundles.size() == 0 && bundleExecutionPlan.uninstallBundles.size() == 0 && bundleExecutionPlan.updateBundles.size() == 0 && bundleExecutionPlan.changeStartLevelIfInitialBundleStartLevelChangesOnBundles.size() != 0 && bundleExecutionPlan.higherStartLevelOnBundles.size() != 0 && bundleExecutionPlan.lowerStartLevelOnBundles.size() != 0 && bundleExecutionPlan.setInitialStartLevelOnBundles.size() != 0 && bundleExecutionPlan.setStartLevelFromInitialBundles.size() != 0 && bundleExecutionPlan.startStoppedBundles.size() != 0 && bundleExecutionPlan.stopStartedBundles.size() != 0; } private void lowerBundleStartLevelWhereNecessary(final BundleExecutionPlan bundleExecutionPlan, final int currentInitialBundleStartLevel, final int newInitialBundleStartLevel, final RemoteOSGiManager remoteOSGiManager) { if (newInitialBundleStartLevel < currentInitialBundleStartLevel) { for (DistributableArtifact dArtifact : bundleExecutionPlan.changeStartLevelIfInitialBundleStartLevelChangesOnBundles) { // CS_DISABLE_LINE_LENGTH remoteOSGiManager.setBundleStartLevel(toBundleSNV(dArtifact), newInitialBundleStartLevel); } } for (DistributableArtifact dArtifact : bundleExecutionPlan.lowerStartLevelOnBundles) { remoteOSGiManager.setBundleStartLevel(toBundleSNV(dArtifact), resolveStartLevel(dArtifact)); } for (Entry<DistributableArtifact, Integer> dArtifactWithOldSL : bundleExecutionPlan.setInitialStartLevelOnBundles // CS_DISABLE_LINE_LENGTH .entrySet()) { int oldStartLevel = dArtifactWithOldSL.getValue(); if (oldStartLevel > newInitialBundleStartLevel) { remoteOSGiManager.setBundleStartLevel(toBundleSNV(dArtifactWithOldSL.getKey()), newInitialBundleStartLevel); } } for (DistributableArtifact dArtifact : bundleExecutionPlan.setStartLevelFromInitialBundles) { Integer startLevel = resolveStartLevel(dArtifact); if (startLevel.compareTo(newInitialBundleStartLevel) < 0) { remoteOSGiManager.setBundleStartLevel(toBundleSNV(dArtifact), startLevel); } } } private void parseParsables(final File distFolderFile, final EnvironmentType distributedEnvironment, final Collection<DistributableArtifact> distributedArtifacts, final FileManager fileManager) throws MojoExecutionException { Map<String, Object> vars = new HashMap<>(); vars.put("distributedEnvironment", distributedEnvironment); vars.put("distributedArtifacts", distributedArtifacts); vars.put(VAR_DIST_UTIL, new DistUtil()); ParsablesType parsables = distributedEnvironment.getParsables(); if (parsables != null) { List<ParsableType> parsable = parsables.getParsable(); for (ParsableType p : parsable) { String path = p.getPath(); File parsableFile = new File(distFolderFile, path).getAbsoluteFile(); if (!parsableFile.exists()) { throw new MojoExecutionException( "File that should be parsed does not exist: " + "[" + parsableFile.getAbsolutePath() + "]"); } try { String encoding = p.getEncoding(); if (encoding == null) { encoding = "UTF8"; } fileManager.replaceFileWithParsed(parsableFile, vars, encoding, p.getTemplateEngine(), false); } catch (IOException e) { throw new MojoExecutionException( "Could not replace parsable with parsed content: [" + p.getPath() + "]", e); } } } } private Collection<DistributableArtifact> processArtifacts(final EnvironmentType environment) { List<DistributableArtifact> result = new ArrayList<>(); if (environment == null) { return result; } ArtifactsType artifacts = environment.getArtifacts(); if (artifacts == null) { return result; } List<ArtifactType> artifactList = artifacts.getArtifact(); for (ArtifactType artifact : artifactList) { DistributableArtifact distributableArtifact = new DistributableArtifact(); distributableArtifact.targetFile = artifact.getTargetFile(); distributableArtifact.targetFolder = artifact.getTargetFolder(); distributableArtifact.coordinates = artifact.getCoordinates(); // TODO resolve file and downloadURL if possible PropertiesType properties = artifact.getProperties(); if (properties != null) { for (EntryType entry : properties.getProperty()) { distributableArtifact.properties.put(entry.getKey(), entry.getValue()); } } result.add(distributableArtifact); } return result; } private void processConfigurationTemplate(final File configFile, final Collection<DistributableArtifact> distributableArtifacts, final EnvironmentConfiguration environment, final FileManager fileManager) throws MojoExecutionException, MojoFailureException { LaunchConfig launchConfig = environment.getLaunchConfig(); if (this.launchConfig != null) { launchConfig = this.launchConfig.createLaunchConfigForEnvironment(launchConfig); } if (launchConfig == null) { launchConfig = new LaunchConfig(); } checkAndAddReservedLaunchConfigurationProperties(environment, launchConfig); Map<String, Object> vars = new HashMap<>(); vars.put("environmentId", environment.getId()); vars.put("frameworkStartLevel", environment.getFrameworkStartLevel()); vars.put("bundleStartLevel", environment.getInitialBundleStartLevel()); vars.put("distributableArtifacts", distributableArtifacts); vars.put("runtimePathRegexes", environment.getRuntimePathRegexes()); vars.put("launchConfig", launchConfig); vars.put(VAR_DIST_UTIL, new DistUtil()); try { fileManager.replaceFileWithParsed(configFile, vars, "UTF8", TemplateEnginesType.XML, true); } catch (IOException e) { throw new MojoExecutionException( "Could not run velocity on configuration file: " + configFile.getName(), e); } } /** * Reading up the content of each /META-INF/eosgi-frameworks.properties file from the classpath of * the plugin. * * @return The merged properties file. * @throws IOException * if a read error occurs. */ private Properties readDefaultFrameworkPops() throws IOException { Enumeration<URL> resources = this.getClass().getClassLoader() .getResources("META-INF/eosgi-frameworks.properties"); Properties result = new Properties(); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); Properties tmpProps = new Properties(); InputStream inputStream = resource.openStream(); try { tmpProps.load(inputStream); } finally { if (inputStream != null) { inputStream.close(); } } result.putAll(tmpProps); } return result; } private ClassLoader resolveAttachAPIClassLoader() { Object classLoaderObj = session.getRequest().getData() .get(DistConstants.MAVEN_EXECUTION_REQUEST_DATA_KEY_ATTACH_API_CLASSLOADER); if (classLoaderObj != null) { return (ClassLoader) classLoaderObj; } return DistMojo.class.getClassLoader(); } private String resolveBundleAction(final DistributableArtifact dArtifact) { String bundleActionString = dArtifact.properties.get(EOSGiConstants.ARTIFACT_PROPERTY_BUNDLE_ACTION); if (bundleActionString == null) { return null; } return bundleActionString.toLowerCase(); } private Artifact resolveDistPackage(final String frameworkArtifact) throws MojoExecutionException { String[] distPackageIdParts; try { distPackageIdParts = resolveDistPackageId(frameworkArtifact); } catch (IOException e) { throw new MojoExecutionException("Could not get distribution package", e); } ArtifactRequest artifactRequest = new ArtifactRequest(); artifactRequest.setArtifact( new DefaultArtifact(distPackageIdParts[0], distPackageIdParts[1], "zip", distPackageIdParts[2])); return artifactResolver.resolve(artifactRequest); } /** * Resolves the maven artifact id of the distribution package that should be used. * * @return A three length string array that contains the groupId, artifactId and version of the * dist package. * @throws IOException * if the resrources of the default framework id configurations cannot be read. * @throws MojoExecutionException * if the distPackage expression configured for this plugin has wrong format. */ private String[] resolveDistPackageId(final String pFrameworkArtifact) throws IOException, MojoExecutionException { String frameworkArtifact = (pFrameworkArtifact != null) ? pFrameworkArtifact : DistConstants.DEFAULT_ENVIRONMENT_FRAMEWORK; String[] distPackageParts = frameworkArtifact.split("\\:"); if (distPackageParts.length == 1) { Properties defaultFrameworkPops = readDefaultFrameworkPops(); String defaultFrameworkDistPackage = defaultFrameworkPops.getProperty(frameworkArtifact); if (defaultFrameworkDistPackage == null) { getLog().error( "Could not find entry in any of the " + "/META-INF/eosgi-frameworks.properites configuration " + "files on the classpath for the framework id " + frameworkArtifact); throw new MojoExecutionException( "Could not find framework dist package [" + frameworkArtifact + "]"); } else { distPackageParts = defaultFrameworkDistPackage.split("\\:"); getLog().info("Dist package definition '" + frameworkArtifact + "' was resolved to be '" + defaultFrameworkDistPackage + "'"); } } if (distPackageParts.length != MAVEN_ARTIFACT_ID_PART_NUM) { throw new MojoExecutionException( "Invalid distribution package id format: " + frameworkArtifact); } return distPackageParts; } private int resolveFrameworkStartLevelAfterUpgrade(final Integer frameworkStartLevel, final int originalFrameworkStartLevel) { return (frameworkStartLevel != null) ? frameworkStartLevel : originalFrameworkStartLevel; } private Set<DistributableArtifact> resolveJustStartedActiveBundles( final RemoteOSGiManager remoteOSGiManager, final Map<BundleSNV, DistributableArtifact> justStartedBundleByUniqueLabel) { RuntimeBundleInfo[] runtimeBundleInfoArray = remoteOSGiManager.getRuntimeBundleInfoArray(); Set<DistributableArtifact> activeJustStartedBundleSet = new HashSet<>(); for (RuntimeBundleInfo runtimeBundleInfo : runtimeBundleInfoArray) { DistributableArtifact bundleData = justStartedBundleByUniqueLabel.get(toBundleSNV(runtimeBundleInfo)); if (runtimeBundleInfo.state == Bundle.ACTIVE && bundleData != null) { activeJustStartedBundleSet.add(bundleData); } } return activeJustStartedBundleSet; } private Artifact resolveMavenArtifactByArtifactType(final DistributableArtifact artifact) throws MojoExecutionException { return resolveArtifact(new DefaultArtifact(artifact.coordinates, artifact.properties)); } private int resolveNecessaryStartlevel(final BundleExecutionPlan bundleExecutionPlan, final int originalFrameworkStartLevel, final int initialBundleStartLevel) { int newStartLevel = originalFrameworkStartLevel; Integer lowestBundleStartLevel = bundleExecutionPlan.lowestStartLevel; if (lowestBundleStartLevel != null && lowestBundleStartLevel.compareTo(newStartLevel) < 0) { newStartLevel = lowestBundleStartLevel; } if (initialBundleStartLevel < newStartLevel && bundleExecutionPlan.changeStartLevelIfInitialBundleStartLevelChangesOnBundles.size() > 0 && bundleExecutionPlan.installBundles.size() > 0 && bundleExecutionPlan.setInitialStartLevelOnBundles.size() > 0 && bundleExecutionPlan.setStartLevelFromInitialBundles.size() > 0) { newStartLevel = initialBundleStartLevel; } return newStartLevel; } private List<DistributableArtifact> resolveResolvedBundlesInJustStartedActiveBundleDependencyClosure(// CS_DISABLE_LINE_LENGTH final Map<BundleSNV, DistributableArtifact> shouldBeActiveBundleByUniqueLabel, final RuntimeBundleInfo[] dependencyClosure) { List<DistributableArtifact> bundlesInClosureToStart = new ArrayList<>(); for (RuntimeBundleInfo runtimeBundleInfo : dependencyClosure) { if (runtimeBundleInfo.state == Bundle.RESOLVED) { DistributableArtifact bundleData = shouldBeActiveBundleByUniqueLabel.get(toBundleSNV(runtimeBundleInfo)); if (bundleData != null) { bundlesInClosureToStart.add(bundleData); } } } return bundlesInClosureToStart; } private Integer resolveStartLevel(final DistributableArtifact distributableArtifact) { String startLevelString = distributableArtifact.properties.get("bundle.startLevel"); if (startLevelString == null) { return null; } return Integer.parseInt(startLevelString); } private void setStartLevelOnNewlyInstalledBundles( final Collection<DistributableArtifact> installBundles, final RemoteOSGiManager remoteOSGiManager) { for (DistributableArtifact distributableArtifact : installBundles) { Integer startLevelString = resolveStartLevel(distributableArtifact); if (startLevelString != null) { remoteOSGiManager.setBundleStartLevel(toBundleSNV(distributableArtifact), startLevelString); } } } private void startBundlesWhereNecessary(final BundleExecutionPlan bundleExecutionPlan, final Collection<DistributableArtifact> distributedArtifacts, final RemoteOSGiManager remoteOSGiManager) { Set<DistributableArtifact> bundlesToStart = new LinkedHashSet<>(bundleExecutionPlan.startStoppedBundles); for (DistributableArtifact dArtifact : bundleExecutionPlan.updateBundles) { if (EOSGiConstants.BUNDLE_ACTION_START.equals(resolveBundleAction(dArtifact))) { bundlesToStart.add(dArtifact); } } for (DistributableArtifact dArtifact : bundleExecutionPlan.installBundles) { if (EOSGiConstants.BUNDLE_ACTION_START.equals(resolveBundleAction(dArtifact))) { bundlesToStart.add(dArtifact); } } remoteOSGiManager.startBundles(toBundleSNVs(bundlesToStart)); startResolvedBundlesOfJustStartedActiveBundlesDependencies(bundlesToStart, distributedArtifacts, remoteOSGiManager); } private void startResolvedBundlesOfJustStartedActiveBundlesDependencies( final Collection<DistributableArtifact> justStartedBundles, final Collection<DistributableArtifact> distributedArtifacts, final RemoteOSGiManager remoteOSGiManager) { Map<BundleSNV, DistributableArtifact> justStartedBundleByUniqueLabel = createJustStartedBundleByUniqueLabelMap(justStartedBundles); Set<DistributableArtifact> activeJustStartedBundleSet = resolveJustStartedActiveBundles(remoteOSGiManager, justStartedBundleByUniqueLabel); Map<BundleSNV, DistributableArtifact> shouldBeActiveBundleByUniqueLabel = createStartActionBundleByUniqueLabelMap( distributedArtifacts); RuntimeBundleInfo[] dependencyClosure = remoteOSGiManager .getDependencyClosure(toBundleSNVs(activeJustStartedBundleSet)); List<DistributableArtifact> bundlesInClosureToStart = resolveResolvedBundlesInJustStartedActiveBundleDependencyClosure( shouldBeActiveBundleByUniqueLabel, dependencyClosure); remoteOSGiManager.startBundles(toBundleSNVs(bundlesInClosureToStart)); } private BundleSNV toBundleSNV(final DistributableArtifact distributableArtifact) { String symbolicName = distributableArtifact.properties.get("bundle.symbolicName"); String version = distributableArtifact.properties.get("bundle.version"); return new BundleSNV(symbolicName, version); } private Object toBundleSNV(final RuntimeBundleInfo runtimeBundleInfo) { return new BundleSNV(runtimeBundleInfo.symbolicName, runtimeBundleInfo.version); } private Map<BundleSNV, String> toBundleSNVLocationMap( final Collection<DistributableArtifact> installBundles) { Map<BundleSNV, String> result = new LinkedHashMap<>(); for (DistributableArtifact distributableArtifact : installBundles) { BundleSNV bundleSNV = toBundleSNV(distributableArtifact); String location = distributableArtifact.properties.get("bundle.location"); result.put(bundleSNV, location); } return result; } private Collection<BundleSNV> toBundleSNVs( final Collection<DistributableArtifact> distributableArtifacts) { List<BundleSNV> result = new ArrayList<>(distributableArtifacts.size()); for (DistributableArtifact distributableArtifact : distributableArtifacts) { result.add(toBundleSNV(distributableArtifact)); } return result; } private File unpackDistConfigFileToNewTempFile(final File distPackageFile, final FileManager fileManager) { try { File environmentConfigurationTempFile = File.createTempFile("eosgi", DistConstants.FILE_NAME_EOSGI_DIST_CONFIG); fileManager.unpackZipEntry(distPackageFile, environmentConfigurationTempFile, DistConstants.FILE_NAME_EOSGI_DIST_CONFIG); return environmentConfigurationTempFile; } catch (IOException e) { throw new UncheckedIOException(e); } } }